#include <I2C.h>

#if I2C_DEBUG
#include <usart.h>
#endif

unsigned char ROM_addr = 0;
unsigned char Device_addr = 0;
unsigned char RT_flag = 0;
/*void I2C1_ER_IRQHandler(void)
{
	SR = I2C1->SR2;
	SR <<= 16;
	SR |= I2C1->SR1;
	LED0 = 1;
	I2C1->CR1 = 0;
}*/
void I2C1_EV_IRQHandler(void)
{
	if((I2C1->SR1 & SB) == SB)
	{
		if(RT_flag & STAGE)
			I2C1->DR = Device_addr|0x01;
		else
			I2C1->DR = Device_addr&0xFE;
	}
	if((I2C1->SR1 & ADDR) == ADDR)
	{
		I2C1->SR2;
		if((RT_flag & STAGE) == 0 && (RT_flag & TxMODE) == 0)
		{
			I2C1->DR = ROM_addr;
			RT_flag |= STAGE;
		}
	}
	if((I2C1->SR1 & BTF) == BTF)
	{
		if (RT_flag & STAGE)
		{
			I2C1->CR1 |= START|ACK;
		}
		else if(RT_flag & TCF)
		{	//master transmitter
			I2C1->CR1 |= STOP;
			I2C1->CR2 &= ~(DMAEN);
		}
	}
	if((I2C1->SR1 & STOPF) == STOPF)	//STOPF = 1
		I2C1->CR1 = ACK|PE;				//ACK & PE
}
void IIC1_Init(void)
{
	GPIOB_Enable();
	GPIO_config(GPIOB,6,AF_OD);//I2C1_SCL
	GPIO_config(GPIOB,7,AF_OD);//I2C1_SDA
	
	RCC->APB1ENR |= 1<<21;
	
	I2C1->OAR1 = 0x4000;
	I2C1->CR2 = 0x0024;	//36MHz，不开中断
	I2C1->CCR = 180;	//36MHz，36M/360 = 100kHz，占空比0.5
	I2C1->TRISE = 72;	//根据I2C标准配置
	
	MY_NVIC_Init(1,2,I2C1_EV_IRQn,2);
}
//配置为推挽有可能导致MOS管直通，不建议
void IIC2_Init(void)
{
	GPIOB_Enable();
	GPIO_config(GPIOB,10,AF_OD);//I2C2_SCL
	GPIO_config(GPIOB,11,AF_OD);//I2C2_SDA
	
	RCC->APB1ENR |= 1<<22;

	I2C2->OAR1 = 0x40B0;	//7bits slave mode, slave address = 0xB0
	I2C2->CR2 = 0x0024;
	I2C2->CCR = 180;
	I2C2->TRISE = 72;
	//官方推荐设置为最高优先级，DMA也推荐用最高优先级
	//MY_NVIC_Init(0,0,I2C2_EV_IRQn ,2);
}
//addr[7:1]:address of slave device
//data:Rx_Buffer pointer
//data_num:numbers of bytes to read. support up to 256 bytes
unsigned char IIC1_DMA_Read(struct IIC_conf_info *config_info)
{
	struct dma_config_info conf_info;

	if(config_info->data_num == 0)
		return 4;
	Device_addr = config_info->slave_addr;
	RT_flag = IN_ADDR;
	if(config_info->flag & IN_ADDR)
		ROM_addr = config_info->addr;
	else
		RT_flag |= STAGE;
	
	I2C1->CR1 = PE;		//Enable I2C1
	I2C1->CR1 |= START;
	I2C1->CR2 |= ITEVT|LAST;

	conf_info.channel = DMA1_Channel7;
	conf_info.cpar    = (void *)&(I2C1->DR);
	conf_info.cmar    = config_info->data;
	conf_info.cndtr   = config_info->data_num;
	conf_info.ccr     = 0x0080;	//top priority
	DMA1_Config(&conf_info);
	
	I2C1->CR2 |= DMAEN;
	return 0;
}
//Read data from 24C02
//addr[10-8]作为器件地址，addr[7-1]作为片内地址，addr[0]器件写使能
//data：接收缓冲
//data_num：要接收的字节数
unsigned char E2PROM_Read(unsigned short addr,unsigned char *data,unsigned char data_num)
{
	unsigned short times=0;
	unsigned char offset = 0;
	
	if(data_num == 0 || addr & 0xF800)
		return 4;
	
	I2C1->CR1 = PE;	//Enable I2C1
	
	//choose chip & write ROM address
	I2C1->CR1 |= START;	//start
	//check for SB == 1
	while((I2C1->SR1 & SB) == 0 && times != 720)
		++times;
	if(times != 720)
		times = 0;
	else
		return 1;//can't send start condition within reasonable time
	//send equipment address & check for ADDR == 1
	I2C1->DR = (unsigned char)(0xA0 + (addr>>7)) & 0xFE;	//writing address & slave read
	while((I2C1->SR1 & ADDR) == 0 && times != 1500)	//720 also work here
		++times;
	if(times != 1500)
		times = 0;
	else
		return 2;//slave didn't ACK
	//clear ADDR & send ROM address
	I2C1->SR2;	//read SR1 & SR2 to clear ADDR
	I2C1->DR = addr;
	while((I2C1->SR1 & BTF) == 0 && times != 1500)
		++times;//wait for addr transit finish
	if(times != 1500)
		times=0;
	else
		return 3;//can't send ROM_addr

	//read data
	//send equipment address
	I2C1->CR1 |= START|ACK;	//re-start & ACK
	//check for SB == 1
	while((I2C1->SR1 & SB) == 0 && times != 720)
		++times;
	if(times != 720)
		times = 0;
	else
		return 4;//can't send start condition within reasonable time
	//send equipment address & check for ADDR == 1
	I2C1->DR = (unsigned char)(0xA0 + (addr>>7)) | 0x01;	//writing address & slave write
	while((I2C1->SR1 & ADDR) == 0 && times != 1500)	//720 also work here
		++times;
	if(times != 1500)
		times = 0;
	else
		return 5;//slave didn't ACK
	if((I2C1->SR2 & 0x0005) == 0x0001)	//Master Receiver
	{
		for(;offset < data_num;++offset)
		{
			if(offset == (data_num-1))
				I2C1->CR1 = STOP|PE;	//NACK & STOP
			while((I2C1->SR1 & RxNE) == 0 && times != 7200)
				++times;
			if(times != 7200)
				*(data + offset) = I2C1->DR;
			else
			{
				I2C1->CR1 = STOP|PE;
				return 6;//
			}
			times = 0;
		}
	}
	//I2C1->CR1 &= 0xFFFE;	//disable I2C1
	return 0;	//done well
}
//简单器件不需要送片内地址，所以可以送完器件地址后直接读
//很久之前写的，而且我没有器件，所以没有测试
/*unsigned char IIC2_ReadBytes(unsigned char addr,unsigned char *data,unsigned char data_num)
{
	unsigned short times=0;
	unsigned char offset = 0;
	
	if(data_num == 0)
		return 4;
	
	I2C2->CR1 = 0x0001;	//Enable I2C2
	addr |= 0x01;	//slave write
	I2C2->CR1 |= 0x0100;	//start
	//check for SB == 1
	while((I2C2->SR1 & 0x0001) != 0x0001 && times != 1500)//720 also work here! unbelievale
		++times;
	if(times != 1500)
		times = 0;
	else
		return 1;//can't send start condition within reasonable time
	//send address & check for ADDR == 1
	I2C2->DR = addr;	//writing address
	while((I2C2->SR1 & 0x0002) != 0x0002 && times != 1500)
		++times;
	if(times != 1500)
		times = 0;
	else
		return 2;//slave didn't ACK
	
	if(I2C2->SR2 & 0x0001)	//read SR1 & SR2 to clear ADDR
	{
		I2C2->CR1 |= 0x0400;
		for(;offset < data_num;++offset)
		{
			if(offset == (data_num-1))
				I2C2->CR1 = 0x0201;	//NACK & STOP
			while((I2C2->SR1 & 0x0040) != 0x0040 && times != 7200)
				++times;
			if(times != 7200)
				*(data + offset) = I2C2->DR;
			else
			{
				#if I2C_DEBUG
				USART1->DR = offset;
				#endif
				I2C2->CR1 = 0x0201;
				return 3;//
			}
			times = 0;
		}
	}
	//I2C2->CR1 &= 0xFFFE;
	return 0;	//done well
}*/
//主动发送
//注意：24Cxx写数据和下一次操作之间需要间隔一段时间
//addr[7-1]:器件地址
unsigned char IIC1_WriteBytes(unsigned char addr,unsigned char *data,unsigned char data_num)
{
	unsigned short times=0;
	unsigned char offset = 0;

	if(data_num == 0)
		return 4;

	addr &= 0xFE;		//slave: receiver
	I2C1->CR1 = 0x0001;	//Enable I2C1
	I2C1->CR1 |= 0x0500;//start & ACK
	
	//check for SB==1
	while((I2C1->SR1 & SB) != SB && times != 720)
		++times;
	if(times != 720)
		times = 0;
	else
		return 1;//time out
	//send address & check for ADDR == 1
	I2C1->DR = addr;
	while((I2C1->SR1 & ADDR) == 0 && times != 1500)
		++times;
	if(times != 1500)
		times = 0;
	else
		return 2;//slave didn't ACK
	I2C1->SR2; 	 //read SR1 & SR2 to clear ADDR
	for(;(offset < data_num) && (times != 8000);++offset)
	{
		times = 0;
		I2C1->DR = *(data + offset);
		/*if(offset == (data_num-1))
			I2C1->CR1 = 0x0201;*/	//STOP
		while((I2C1->SR1 & 0x0084) == 0 && (times != 8000)) //when TxE=1 & BTF!=1
		    ++times;
	}
	if(times == 8000){
		I2C1->CR1 = 0x0201;
		//I2C1->CR1 = 0;
		return 6;
	}
	times = 0;
	while((I2C1->SR1 & 0x0004) == 0 && times !=8000)//BTF=1
		++times;
	I2C1->CR1 = 0x0201;//stop
	if(times == 8000)
		return 2;
	//I2C1->CR1 = 0;
	return 0;
}
